package com.rpoonolly.simplegame.processors;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import javax.vecmath.Vector2d;

import com.rpoonolly.simplegame.Config;
import com.rpoonolly.simplegame.SimpleUserAction;
import com.rpoonolly.simplegame.core.CollisionDetector;
import com.rpoonolly.simplegame.core.CollisionResponder;
import com.rpoonolly.simplegame.core.InputManager;
import com.rpoonolly.simplegame.core.aabb.AABBCollision;
import com.rpoonolly.simplegame.core.aabb.AABBEntity;
import com.rpoonolly.simplegame.core.aabb.DynamicAABBEntity;
import com.rpoonolly.simplegame.core.aabb.EntityGameMap;

/**
 * @author Ryan
 *	
 * class to handle very basic npc logic. Moves the npc towards the player colliding against all collidables. (ignores input) 
 */
public class SimpleNPCProcessor extends DynamicEntityProcessor {
	private List<String> groupsToProcess;
	private List<AABBEntity> npcs;
	
	/**
	 * list of objects that the npc collides with
	 */
	protected List<AABBEntity> collidables = new ArrayList<AABBEntity>();

	/**
	 * if true updates list of collidables on each iteration of process()
	 */
	protected boolean updateCollidables = true;
	
	protected InputManager<SimpleUserAction> inputMngr;

	/**
	 * @param detector
	 * @param responder 
	 * @param groupsToProcess list of groups that this processor should process
	 */
	public SimpleNPCProcessor(
		CollisionDetector<AABBEntity, AABBCollision> detector,
		CollisionResponder<AABBCollision> responder,
		EntityGameMap<AABBEntity> gameMap,
		String... groupsToProcess
	) {
		super(detector, responder, gameMap);
		
		this.groupsToProcess = new ArrayList<String>();
		Collections.addAll(this.groupsToProcess, groupsToProcess);
		npcs = new ArrayList<AABBEntity>();
	}

	@Override
	public void process() {		
		processTime();
		if (Config.isEditModeEnabled.get()) return;
		
		List<AABBEntity> worldObjs = entities.get(Config.ENT_GRP_WORLD_OBJS);
		DynamicAABBEntity player = (DynamicAABBEntity) entities.get(Config.ENT_GRP_PLAYER).get(0);
		
		npcs.clear();
		for (String npcGroupName : groupsToProcess)
			npcs.addAll(entities.get(npcGroupName));
		
		if (updateCollidables) {
			collidables.clear();
			collidables.addAll(worldObjs);
			collidables.addAll(npcs);
		}
		
		for(AABBEntity npc : npcs) {
			processNPCMoveLogic((DynamicAABBEntity) npc, collidables, player.getX(), player.getY(), Config.ENEMY_MAX_SPEED);
		}
	}
	
	/**
	 * handles basic npc move logic. Gets called on all npcs in the groups to process.
	 * 
	 * @param npc npc to move
	 * @param collidables objs that the npc can collide into on it's path
	 * @param targetX xcoord of point to move to
	 * @param targetY ycoord of point to move to
	 * @param maxSpeed maximum speed that the npc can move
	 */
	protected void processNPCMoveLogic(
			DynamicAABBEntity npc, 
			List<AABBEntity> collidables, 
			int targetX, 
			int targetY,
			double maxSpeed
	) {
		AABBCollision minCollision;
		Vector2d v = npc.getDirection();
		v.x = 0;
		v.y = 0;
		
		double dx = targetX - npc.getX();
		double dy = targetY - npc.getY();
		
		//limiting movement by maxSpeed
		if (dx != 0 && dy != 0) {
			if (Math.abs(dx) > Math.abs(dy)) {
				v.x = maxSpeed * dt / 1000;
				v.y = v.x * Math.abs(dy / dx);
			} else {
				v.y = maxSpeed * dt / 1000;
				v.x = v.y * Math.abs(dx / dy);
			}
			
			if (dx < 0) v.x *= -1;
			if (dy < 0) v.y *= -1;
		}
		
		minCollision = checkGroupCollision(npc, collidables);
		if (minCollision != null)
			v = collisionResponder.collisionRespond(minCollision);
		
		npc.setX((int) (npc.getX() + v.x));
		npc.setY((int) (npc.getY() + v.y));
	}
}
